package com.ruoyi.app.util;

import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;

@Slf4j
public class RsaUtil {

    /** 密钥长度，用来初始化 */
    private static final int KEYSIZE = 1024;
    
    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;
    
    /**
	 * RSA最大解密密文大小
	 */
	private static final int MAX_DECRYPT_BLOCK = 128;


    private static final String ALGORITHM = "RSA";
    
    //获取公钥
    public static PublicKey getPublickey(String publickey) throws Exception{
        byte[] keyBytes = Base64.decodeBase64(publickey);

        X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        PublicKey pubKey = keyFactory.generatePublic(bobPubKeySpec);

        return pubKey;
    }
    
	//获取私钥
    public static PrivateKey getPrivateKey(String privateKey) throws Exception{
        byte[] keyBytes = Base64.decodeBase64(privateKey);

        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);  
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);  
        PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);

        return privateK;
    }
    
    //私钥加密
    public static byte[] encryptByPrivateKey(byte[] data, PrivateKey privateKey) throws Exception{
    	Cipher cipher;
        byte[] output;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
    	
        try{
        	cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            
            int inputLen = data.length;
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段解密
            while (inputLen - offSet > 0){
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK)
                {
                    cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
                } else
                {
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;
            }
            output = out.toByteArray();
        } catch (Exception e){
            log.error("私钥加密异常：", e);
            throw e;
        }finally{
            out.close();
        }

        return output;
    }
    
    // 公钥解密
    public static byte[] decryptByPublicKey(byte[] data, PublicKey publickey) throws Exception{
    	Cipher cipher;
        byte[] output;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        
        try{
            cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, publickey);

            int inputLen = data.length;
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段解密
            while (inputLen - offSet > 0)
            {
                if (inputLen - offSet > MAX_DECRYPT_BLOCK)
                {
                    cache = cipher.doFinal(data, offSet, MAX_DECRYPT_BLOCK);
                } else
                {
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_DECRYPT_BLOCK;
            }
            output = out.toByteArray();
        } catch (Exception e){
            log.error("公钥解密异常：", e);
            throw e;
        }finally{
        	out.close();
        }

        return output;
    }
    
    //公钥加密
    public static byte[] encryptByPublickey(byte[] source,PublicKey publickey) throws Exception{
        Cipher cipher;
        byte[] output;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        
        try{
            cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, publickey);

            int inputLen = source.length;
            int offSet   = 0;
            int i = 0;
            byte[] cache;
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(source, offSet, MAX_ENCRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(source, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;
            }

            output = out.toByteArray();
        }catch(Exception e){
            throw e;
        }finally{
            out.close();
        }
        
        return output;
    }
    
    //私钥解密
	public static byte[] decryptByPrivateKey(byte[] encryptedData, PrivateKey privateKey) throws Exception {    
		Cipher cipher;
		byte[] decryptedData;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		
		try{
	        cipher = Cipher.getInstance(ALGORITHM);  
	        cipher.init(Cipher.DECRYPT_MODE, privateKey); 
	        
	        int inputLen = encryptedData.length;  
	          
	        int offSet = 0;  
	        byte[] cache;  
	        int i = 0;  
	        // 对数据分段解密  
	        while (inputLen - offSet > 0) {  
	            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {  
	                cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);  
	            } else {  
	                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);  
	            }  
	            out.write(cache, 0, cache.length);  
	            i++;  
	            offSet = i * MAX_DECRYPT_BLOCK;  
	        }  
	        decryptedData = out.toByteArray();
		}catch(Exception e){
            throw e;
        }finally{
            out.close();
        }
		
        return decryptedData;  
    }
}
